/**
 *
 * The MIT License
 *
 * Copyright (c) 2009 Ben Suter. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.macdadi.ks.client.components;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.core.client.GWT;
import org.macdadi.core.client.domain.DataService;
import org.macdadi.core.client.domain.User;
import org.macdadi.core.client.domain.StakeholderGroup;
import org.macdadi.core.client.auth.AuthorizationException;
import org.macdadi.ks.client.ViewContainer;

/**
 * @author Ben Suter <ben.suter@gmail.com>
 */
public class StakeholderList extends Composite
{
    public static final String CSS_CLASS = "macdadi-StakeholderList";
    protected ViewContainer container;
    protected StakeholderListListener listener;
    protected ListBox lb;

    public StakeholderList(ViewContainer container)
    {
        this.container = container;
        setupView();
    }

    public void populate(int project, boolean addEntryForAll) {
        lb.clear();
        fillAvailableStakeholders(lb, project, addEntryForAll);
    }

    protected void setupView()
    {
        lb = new ListBox();

        lb.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                boolean groupSelected = false;
                int selectedID = -1;
                String value;

                if (lb.getSelectedIndex() > 0) {
                    try {
                        value = lb.getValue(lb.getSelectedIndex());
                        if ( value.startsWith("g") ) {
                            groupSelected = true;
                            value = value.substring(1);
                        }

                        selectedID = Integer.parseInt(value);
                    } catch (Exception e) {
                        selectedID = -1;
                    }
                }

                listener.selectionChanged(selectedID, groupSelected);
            }
        });

        initWidget(lb);
        setStyleName(CSS_CLASS);
    }

    /**
     * Fills the specified list with all stakeholders from this project, and adds an entry
     * for "all stakeholders", to aggregate. If the current visitor is logged in and is a stakeholder
     * in this project, pre-select their entry - otherwise, leave "all stakeholders" preselected.
     *
     * @param choices
     */
    protected void fillAvailableStakeholders(final ListBox choices, int project, boolean addEntryForAll)
    {        
        if ( addEntryForAll ) {
            lb.addItem("All Stakeholders (cumulative)", "-1");
            lb.setSelectedIndex(0);
        }

        DataService.App.getInstance().getStakeholderGroups(project, container.getCurrentAuthToken(), new AsyncCallback() {
            public void onFailure(Throwable caught)
            {
                displayError("Unable to retrieve the available stakeholders: " + caught.getMessage(), caught);
                if (caught instanceof AuthorizationException) {
                    displayError("Please login to view available stakeholders", caught);
                }
            }

            /**
             * If the result is null this is interpreted as failure.
             *
             * @param result the result of the async call, should be an array of stakeholdergroups
             */
            public void onSuccess(Object result)
            {
                if (result == null || !(result instanceof StakeholderGroup[])) {
                    displayError("Unable to retrieve the available stakeholders", null);
                    return;
                }

                /* If the current user is logged in, check whether they are a member of any of these
                 * groups. If so, select them the first time they appear.
                 */
                int currentUserId = -1;
                boolean didSelectCurrentUser = false;
                if ( container.getCurrentUser() != null ) {
                    currentUserId = container.getCurrentUser().getId();
                }

                StakeholderGroup[] groups = (StakeholderGroup[]) result;
                for (int i = 0; i < groups.length; i++) {
                    /* First, add the group. Prefix ID of groups with "g" to differentiate from users */
                    choices.addItem(groups[i].getName(), "g" + Integer.toString(groups[i].getId()));

                    /* Then add all the group members */
                    for (int j = 0; j < groups[i].getNumMembers(); j++) {
                        User member = groups[i].getMember(j);
                        /* Indent stakeholders a few spaces relative to group */
                        choices.addItem("    " + member.getName(), Integer.toString(member.getId()));

                        if ( ! didSelectCurrentUser && member.getId() == currentUserId ) {
                            choices.setSelectedIndex(choices.getItemCount() - 1);
                            didSelectCurrentUser = true;
                        }
                    }
                }

                /* If anything was selected while populating the list, it is either -1 for all, or a user id, so notify the listener */
                if ( listener != null && lb.getSelectedIndex() >= 0 ) {
                    listener.selectionChanged(Integer.parseInt(lb.getValue(lb.getSelectedIndex())), false);
                }
            }
        });
    }

    protected void displayError(String message, Throwable error)
    {
        // TODO: show the message as user feedback
        GWT.log(message, error);
    }

    public interface StakeholderListListener
    {
        public void selectionChanged(int selectedID, boolean isGroup);
    }

    public void setListener(StakeholderListListener listener) {
        this.listener = listener;
    }
}
